home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
050
/
pulldown.arc
/
PULLDOWN.PAS
< prev
Wrap
Pascal/Delphi Source File
|
1984-11-12
|
11KB
|
584 lines
{ R+}
Program PullDownMenus;
{
Pull Down Menus in Turbo Pascal
by
Kurt M. Gutzmann
This is a set of routines for constructing a Xerox style
cum Macintosh user interface for Turbo Pascal programs.
Menus are loaded from a menu data file at start up.
The procedure RunMenus is a skeleton with a CASE statement
filled by the programmer to drive his particular menu
tree.
A sample menu data file and a fleshing out of the RunMenus
procedure is done here as an example of how to use PullDowns.
}
const
MaxItems=10; {Max Items on a Menu Bar}
MaxMenus=10; {Max Menus}
Width=11; {Width of Pull Down Fields}
Type
VideoMode =(Norm,Rev,Hi,Und,RevHi,Blink,BlinkHi,RevBlink,RevBlinkHi);
MaxString = String[255];
stringW = string[Width];
ProtoMenu = record
NumEntry :array[0..MaxItems] of integer;
Menu:array[0..MaxItems] of array[0..MaxItems] of stringW;
MenuName:stringW;
NoItems:integer;
end;
MenuPtr = ^ProtoMenu;
MenuAry = array[1..MaxMenus] of MenuPtr;
var
NumMenus:integer;
Menus:MenuAry;
exit:boolean;
VideoSeg:integer;{points to $B000 or $B800 for color or mono}
botbox:maxstring;
function ColorMonitor:boolean;
{returns TRUE if a Color monitor is installed}
type regpack = record
ax,bx,cx,dx,bp,si,di,ds,es,flags:integer;end;
var regs:regpack;
al:integer;
begin
regs.ax:=15 shl 8;
intr($10,regs);
al:=Lo(regs.ax);
if al=$7 then ColorMonitor:=false else ColorMonitor:=true;
end;
Procedure SetVideoSeg;
begin
if colormonitor then VideoSeg:=$B800 else VideoSeg:=$B000
end;
Procedure SetCursor(HiScan,LowScan:byte);
type regpack = record
ax,bx,cx,dx,bp,si,di,ds,es,flags:integer;end;
var regs:regpack;
begin
regs.ax:=1 shl 8;
regs.cx:=HiScan shl 8 + LowScan;
intr($10,regs);
end;
Procedure CursorNormal;
begin
if ColorMonitor then SetCursor(6,7) else SetCursor(10,11);
end;
Procedure CursorBlock;
begin
if ColorMonitor then SetCursor(1,7) else SetCursor(1,14);
end;
Procedure CursorOff;
begin
SetCursor(31,0);
end;
procedure GetKb(var chcode,extcode:integer);
(*Obtains the character and extended codes of a struck key. The codes are
removed from the buffer. This procedure will wait for a keystrike if the
buffer is empty.*)
type
RegPack = record
ax,bx,cx,dx,di,si,ds,es,flags : integer;
end;
var
regs:RegPack;
begin
regs.ax := $0000;
intr($16,regs);
extcode := regs.ax shr 8; ; (*extended code is AH*)
chcode := regs.ax and $00FF; (*character code is AL*)
end;
function inchar(var ch:char;var ex:integer):boolean;{true if ASCII char}
{Returns char and extended code from keyboard}
var chcode,excode:integer;
begin
getkb(chcode,ex);
if chcode=0 then
begin
inchar:=false;
ch:=chr(ex);
end
else
begin
ch:=chr(chcode);
inchar:=true;
if ex<>0 then
if chcode in [8,13,9,27] then
begin
ex:=chcode;
inchar:=false;
end;
end;
end;{inchar}
procedure ReadAt(x,y,nchars:integer;var TheString:maxstring);
{Not Used here, but may be useful to other programs,
performs read from video buffer}
Var
i,j:integer;
Attribute:Byte;
Begin{1}
TheString:='';
j := 2*((y-1)*80+(x-1));{offset in video buffer}
i:=1;
While (i<=nchars) do
begin{3}
TheString:=TheString+chr(ord(Mem[VideoSeg:j]));
i:=i+1;
j:=j+2;
end;{3}
end;{1 of ReadAt}
procedure WriteAt(x,y:integer;WriteMode:VideoMode;TheString:maxstring);
{Memory Mapped write}
Var
i,j,k:integer;
Attribute:Byte;
Begin{1}
case WriteMode of {change these for color terminals}
Norm: Attribute := $07;
Rev: Attribute := $70;
Hi: Attribute := $0F;
Und: Attribute := $01;
RevHi: Attribute := $78;
Blink: Attribute := $87;
BlinkHi: Attribute := $8F;
RevBlink: Attribute := $F0;
RevBlinkHi: Attribute := $F8;
ELSE Attribute := $07;{Normal}
end;
j := 2*((y-1)*80+(x-1));{offset in video buffer}
i:=1;
k:=length(thestring);
While i<=k do
begin
Mem[VideoSeg : j] := Byte(TheString[i]);
Mem[VideoSeg : (j+1)] := Attribute;
i:=i+1;
j:=j+2;
end;
end;{1 of WriteAt}
Procedure LoadMenus(var MenuList:MenuAry);
{loads the menu data file}
var i,j,k:integer;
f:text;
s:maxstring;
Procedure GetAMenu(var M:MenuPtr);
label 99;
var i,j,k:integer;
begin
i:=-1;
j:=0;
{ s has been primed }
M^.MenuName:=s;
readln(f,s);
s:=s+' ';
while (s[1]<>'*') and (not eof(f)) do
begin
if s[1]<>' ' then
begin
if i>=0 then M^.NumEntry[i]:=j;
i:=i+1;
M^.Menu[i,0]:=s;
j:=0;
end
else
if s[1]<>'*' then
begin
j:=j+1;
delete(s,1,1);
M^.Menu[i,j]:=s;
end
else goto 99;
readln(f,s);
s:=s+' ';
end;
99:
M^.NumEntry[i]:=j;
M^.NoItems:=i;
end;{GetAMenu}
begin{Load}
assign(f,'men2.dat'); {alter name for application}
reset(f);
i:=0;
readln(f,s);
while not eof(f) do
begin
i:=i+1;
New(Menus[i]);
GetAMenu(Menus[i]);
end;
NumMenus:=i;
close(f);
{some other initialization here}
botbox:='╚';
for i:=1 to Width do botbox:=botbox+'═';
botbox:=botbox+'╝';
end;{LoadMenu}
procedure DoMenu(var itemsel,entrysel:integer;M:MenuPtr);
{this runs a menu, reads keys etc,}
{itemsel and entrysel are returned}
type
setofkeys=set of 0..132;
var
chc,ex:integer;
ch:char;
validkeys:setofkeys;
asc,selection:boolean;
item,entry:integer;
s1,s2:maxstring;
Procedure PaintMenuBar;
var
i,sx:integer;
begin
clrscr;
writeat(1,1,rev,
' ');
for i:=0 to M^.NoItems do
begin
sx:=2+i*Width;
writeat(sx,1,rev,M^.Menu[i,0]);
end;
end;{PaintMenuBar}
Procedure Bright(ix,ij:integer);
var sx:integer;
s:maxstring;
begin
s:=M^.Menu[ix,ij];
sx:=ix*Width+1;
writeat(sx+1,ij+1,Rev,s)
end;
Procedure UnderScore(ix,ij:integer);
var sx:integer;
s:maxstring;
begin
sx:=ix*Width+1;
s:=M^.Menu[ix,ij];
writeat(sx+1,ij+1,Und,s)
end;
Procedure Normal(ix,ij:integer);
var sx:integer;
s:maxstring;
begin
sx:=ix*Width+1;
if ij=0 then if sx<1 then sx:=1;
s:=M^.Menu[ix,ij];
writeat(sx+1,ij+1,Norm,s);
end;
Procedure PushUp(ix:integer);
var sx,i:integer;
begin
sx:=ix*Width+1;
if sx<1 then sx:=1;
for i:=1 to M^.NumEntry[ix]+1 do
writeat(sx,i+1,Norm,' ');
end;
Procedure PullDown(ix:integer);
const
l:maxstring='║';
r:maxstring='║';
var sx:integer;
s:maxstring;
j:integer;
begin
sx:=ix*Width+1;
for j:=1 to M^.NumEntry[ix] do
begin
s:=l+M^.Menu[ix,j]+r;
writeat(sx,j+1,Norm,s);
end;
if M^.NumEntry[ix]>0 then writeat(sx,M^.NumEntry[ix]+2,Norm,botbox);
end;
begin {DoMenu}
CursorOff;
validkeys:=[13,15,75,9,77,80,72,27];
entry:=1;
item:=0;
PaintMenuBar;
PullDown(0);
Bright(item,entry);
selection:=FALSE;
while not selection do
begin
asc:= Inchar(ch,ex);
if ex=0 then {Ctl-Brk hit}
begin
CursorNormal;
clrscr;
halt;
end;
if not asc then
case ex{tended code} of
13:{CR}
selection:=TRUE;
15, 75:{lefttab,left}
if item>0 then
begin
item:=item-1;
entry:=1;
pushup(item+1);
pulldown(item);
Bright(item,entry);
end;
9, 77:{tab,right}
if item<M^.NoItems then
begin
item:=item+1;
entry:=1;
pushup(item-1);
pulldown(item);
entry:=1;
Bright(item,1);
end;
80:{down}
begin
if entry<M^.NumEntry[item] then
begin
entry:=entry+1;
Normal(item,entry-1);
Bright(item,entry);
end
else
begin
entry:=1;
Normal(item,M^.NumEntry[item]);
Bright(item,entry);
end;
end;
72:{up}
begin
if entry>1 then
begin
entry:=entry-1;
Normal(item,entry+1);
Bright(item,entry);
end
else
begin
entry:=M^.NumEntry[item];
Normal(item,1);
Bright(item,entry);
end;
end;
27:{Esc}
begin
selection:=TRUE;
item:=0;
entry:=0;
end;
end;{case}
end;{while not selection}
itemsel:=item;
entrysel:=entry;
CursorNormal;
end;{DoMenu}
Procedure RunMenus;
{ Skeleton Procedure that you flesh out to run your menu tree.
DoMenu returns item=menu bar item and entry=entry underneath the
item as the selection. Zeros are returned for the escape key.
Compose the CASE index by 100* Active + 10*Item + Entry .
So Menu 2 Item 3 Entry 4 has an index of 234.
Fill in the Case statement to accomodate the returned indices.
}
var
exit:boolean;
ch:char;
Active,index,item,entry:integer;
begin {RunMenu}
exit:=FALSE;
Active:=1;
while not exit do
begin
DoMenu(item,entry,Menus[Active]);
index:=Active*100+item*10+entry;
case index of {fill this in appropriately with structure}
100:exit:=TRUE;
101..104,201..204,301..304: begin
gotoxy(10,10);
writeln(' This is for Information Only');
delay(5000);
end;
111 : begin
Active:=2; {select next Menu}
end;
112 : begin
Active:=3; {select next Menu}
end;
121,122,211,212 : begin
gotoxy(10,10);
writeln(' These Entries Have No Function.');
delay(5000);
end;
131,222: begin
gotoxy(10,10);
write(' Do You Really Want to Quit? ');
readln(ch);
if ch in ['Y','y'] then exit:=TRUE;
end;
221,321,200,300:Active:=1;
311:begin
gotoxy(10,10);
write(' Caesar slowly sipped his snifter,');
writeln(' seized his knees and sneezed.');
delay(5000);
end;
312:begin
gotoxy(10,10);
writeln(' Peter Piper picked a peck of pickled peppers.');
delay(5000);
end;
end;{case}
end;
end;{RunMenus}
begin{main}
CursorNormal;
SetVideoSeg;
LoadMenus(Menus);
RunMenus;
clrscr;
end.